package com.h3c.nem.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eos.common.custom.BusinessException;
import com.eos.common.util.DateUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.h3c.nem.dto.PageQueryDTO;
import com.h3c.nem.dto.SdAllWorkerDTO;
import com.h3c.nem.dto.mapstruct.NewWorkerDTO;
import com.h3c.nem.entity.*;
import com.h3c.nem.enums.CareInfoType;
import com.h3c.nem.mapper.TbCareInfoMapper;
import com.h3c.nem.mapper.TbWorkerGradeMapper;
import com.h3c.nem.service.CommService;
import com.h3c.nem.service.ITbCareInfoService;
import com.h3c.nem.utils.AppBusinessException;
import com.h3c.nem.utils.CommonUtil;
import com.h3c.nem.utils.EosUtils;
import com.h3c.nem.utils.WeChatUtils;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新员工关怀详情信息
 *
 * @author z22968
 * @date 2022/6/9 11:20
 */
@Slf4j
@Service
public class TbCareInfoServiceImpl extends ServiceImpl<TbCareInfoMapper, TbCareInfo> implements ITbCareInfoService {
    @Resource
    TbCareInfoServiceImpl tbCareInfoServiceImpl;
    @Resource
    TbCareInfoMapper tbCareInfoMapper;
    @Resource
    TbCareNoInfoServiceImpl tbCareNoInfoService;
    @Resource
    TbOfferWorkerServiceImpl tbOfferWorkerService;
    @Resource
    SdDeptServiceImpl sdDeptService;
    @Resource
    SdAllWorkerServiceImpl sdAllWorkerService;
    @Resource
    TbCareNoticeSettingServiceImpl tbCareNoticeSettingService;
    @Resource
    TbWorkerGradeServiceImpl tbWorkerGradeService;
    @Resource
    private CommService commService;
    @Resource
    private EosUtils eosUtils;
    @Resource
    private WeChatUtils weChatUtils;
    @Resource
    private TbCareNoticeLogServiceImpl tbCareNoticeLogService;

    @Value("${care.index.url}")
    private String careIndexUrl;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getAllNoticeList() {
        // 获取新员工列表
        // 获取最近一次拉取新员工用的起始时间
        Date startTime = this.getPullNewWorkerStartTime(false);
        List<NewWorkerDTO> newWorker = sdAllWorkerService.getNewWorker(startTime);
        for (NewWorkerDTO newWorkerDTO : newWorker) {
            try {
                List<TbCareInfo> noticeList = getNoticeList(newWorkerDTO);
                if (CollectionUtils.isEmpty(noticeList)) {
                    log.info("该新员工获取推送列表结果为空");
                } else {
                    // 不能用this，this本身就是被代理类
                    // 因此无法通过切面添加事务，因此要使用注入的tbCareInfoServiceImpl
                    tbCareInfoServiceImpl.saveBatchByTransactional(noticeList);
                }
            } catch (Exception e) {
                log.error("获取新员工推送列表出错，工号：{}; ", newWorkerDTO.getWorkerId(), e);
                TbCareNoInfo tbCareNoInfo = new TbCareNoInfo();
                tbCareNoInfo.setWorkerId(newWorkerDTO.getWorkerId());
                String exception = TbCareNoInfoServiceImpl.getExceptionDetail(e);
                tbCareNoInfo.setReason(exception);
                tbCareNoInfoService.save(tbCareNoInfo);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getExcellentNoticeList() {
        // 获取绩效优秀新员工列表
        // 获取上一次绩效优秀的创建时间
        Date startTime = this.getPullNewWorkerStartTime(true);
        QueryWrapper<TbWorkerGrade> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("evaluate_time", startTime).and(tbWorkerGradeQueryWrapper -> {
            tbWorkerGradeQueryWrapper.eq("worker_grade", "A+")
                    .or().eq("worker_grade", "A");
        });
        TbWorkerGradeMapper baseMapper = tbWorkerGradeService.getBaseMapper();
        List<NewWorkerDTO> listByTime = baseMapper.getListByTime(queryWrapper);
        for (NewWorkerDTO newWorkerDTO : listByTime) {
            try {
                // 获取需要通知的领导
                List<TbCareInfo> noticeList = getNoticeLeader(newWorkerDTO);
                // 不能用this，this本身就是被代理类
                // 因此无法通过切面添加事务，因此要使用注入的tbCareInfoServiceImpl
                tbCareInfoServiceImpl.saveBatchByTransactional(noticeList);
            } catch (Exception e) {
                log.error("获取优秀新员工领导推送列表出错，工号：{}; ", newWorkerDTO.getWorkerId(), e);
                TbCareNoInfo tbCareNoInfo = new TbCareNoInfo();
                tbCareNoInfo.setWorkerId(newWorkerDTO.getWorkerId());
                String exception = TbCareNoInfoServiceImpl.getExceptionDetail(e);
                tbCareNoInfo.setReason(exception);
                tbCareNoInfoService.save(tbCareNoInfo);
            }
        }
    }

    @Override
    public List<SdAllWorker> getReceiveNoticeList() throws Exception {
        // 获取全部未发送的通知
        QueryWrapper<TbCareInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.ne("type", CareInfoType.EXCELLENT_PERFORMANCE.getCode())
                .le("notice_time", new Date()) // 预计发送时间 <= 当前时间
                .isNull("actual_notice_time");
        List<TbCareInfo> baseList = tbCareInfoMapper.selectList(queryWrapper);
        // 缓存 用户最近一次收到通知的时间
        HashMap<String, Date> lastDateCache = new HashMap<>();
        // 缓存 需要发送通知的用户
        HashSet<String> userCache = new HashSet<>();
        // 获取用户频率
        TbCareNoticeSetting userSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.FREQUENCY, CareInfoType.USER.getName());
        LocalDate now = LocalDate.now();
        for (TbCareInfo careInfo : baseList) {
            try {
                String oldWorkerId = careInfo.getOldWorkerId();
                // 若已在通知列表中则跳过
                if (userCache.contains(oldWorkerId)) {
                    continue;
                }
                // 重置wrapper
                queryWrapper.clear();
                // 获取该用户最近一次收到通知时间
                Date lastDate = lastDateCache.get(oldWorkerId);
                // 缓存中没有最近一次收到通知时间 则从数据库中获取
                if (lastDate == null) {
                    queryWrapper.ne("type", CareInfoType.EXCELLENT_PERFORMANCE.getCode())
                            .eq("old_worker_id", oldWorkerId)
                            .isNotNull("actual_notice_time")
                            .orderByDesc("actual_notice_time")
                            .last("limit 1");
                    TbCareInfo tmp = tbCareInfoMapper.selectOne(queryWrapper);
                    // 若为null => 从未接受过通知 => 将最近一次接受通知时间设置为2022-01-01
                    if (tmp == null) {
                        lastDate = DateUtils.dateParse("2022-01-01", DateUtils.DATE_PATTERN);
                    } else {
                        lastDate = tmp.getActualNoticeTime();
                    }
                    // 放入缓存
                    lastDateCache.put(oldWorkerId, lastDate);
                }
                // 过滤出今日需要接受通知的人
                // 判断 用户最近一次收到通知时间 + 频率 是否 <= 当前时间， <=则加入需要发送通知set
                LocalDate lastDate2 = CommonUtil.date2LocalDate(lastDate);
                LocalDate plusDays = lastDate2.plusDays(userSetting.getValue());
                if (plusDays.compareTo(now) <= 0) {
                    userCache.add(oldWorkerId);
                }
            } catch (Exception e) {
                log.error("判断用户是否需要通知时发送错误 TbCareInfo：{}", careInfo.toString());
                throw e;
            }
        }
        List<String> workerIdList = new ArrayList<>(userCache);
        List<SdAllWorker> sdAllWorkers = new ArrayList<>();
        if (!CollectionUtils.isEmpty(workerIdList)) {
            // 获取当前在职的用户
            LambdaQueryWrapper<SdAllWorker> workerQueryWrapper = new LambdaQueryWrapper<>();
            workerQueryWrapper.in(SdAllWorker::getWorkerId, workerIdList);
            sdAllWorkers = sdAllWorkerService.getBaseMapper().selectList(workerQueryWrapper);
        }
        return sdAllWorkers;
    }

    @Override
    public List<SdAllWorker> getReceiveNoticeLeaderList() {
        // 获取全部未发送的绩效优秀通知
        LambdaQueryWrapper<TbCareInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbCareInfo::getType, CareInfoType.EXCELLENT_PERFORMANCE.getCode())
                .isNull(TbCareInfo::getActualNoticeTime)
                .groupBy(TbCareInfo::getOldWorkerId);
        List<String> excellentNoticeList = tbCareInfoMapper.getExcellentNoticeList(queryWrapper);
        // 获取当前在职的领导
        LambdaQueryWrapper<SdAllWorker> workerQueryWrapper = new LambdaQueryWrapper<>();
        workerQueryWrapper.in(SdAllWorker::getWorkerId, excellentNoticeList);
        List<SdAllWorker> sdAllWorkers = sdAllWorkerService.getBaseMapper().selectList(workerQueryWrapper);
        return sdAllWorkers;
    }

    @Override
    public void noticeWorkerJob() {
        List<SdAllWorker> receiveNoticeLeaderList = null;
        try {
            receiveNoticeLeaderList = getReceiveNoticeList();
        } catch (Exception e) {
            log.error("获取通知人员列表失败！", e);
            throw new AppBusinessException("获取通知人员列表失败！");
        }
        Boolean jobIsSuccess = true;

        // 获取配置的文案
        TbCareNoticeSetting mailTitle = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.MAIL_CONTENT, "鼓励侧标题");
        TbCareNoticeSetting mailContent = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.MAIL_CONTENT, "鼓励侧正文");
        TbCareNoticeSetting weChatTitle = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.WECHAT_CONTENT, "鼓励侧标题");
        TbCareNoticeSetting weChatContent = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.WECHAT_CONTENT, "鼓励侧正文");
        for (SdAllWorker sdAllWorker : receiveNoticeLeaderList) {
            Boolean isSuccess = true;
            String exception = null;
            // 1. 发送消息
            try {
                // 发送邮件消息
                eosUtils.sendEosMail("zhou.pengb@h3c.com", null,
                        mailTitle.getTextValue(),
                        mailContent.getTextValue() + "( " + sdAllWorker.getWorkerName() + "|" + sdAllWorker.getWorkerId() + " )");
                // 发送企微消息
                weChatUtils.sendWeChatImageMsg("z22968",
                        weChatTitle.getTextValue(),
                        weChatContent.getTextValue() + "( " + sdAllWorker.getWorkerName() + "|" + sdAllWorker.getWorkerId() + " )",
                        weChatUtils.getWeChatOpenUrl(careIndexUrl));
            } catch (Exception e) {
                exception = TbCareNoInfoServiceImpl.getExceptionDetail(e);
                isSuccess = false;
                jobIsSuccess = false;
                log.error("发送消息失败，工号：{}", sdAllWorker.getWorkerId(), e);
            }
            // TODO 异步
            // 2. 修改数据库实际发送时间
            try {
                // 只有两个通知都发送成功，才能修改发送时间
                if (isSuccess) {
                    updateActualNoticeTimeByOldWorkId(sdAllWorker.getWorkerId(), false);
                }
            } catch (Exception e) {
                isSuccess = false;
                jobIsSuccess = false;
                exception += "/n" + TbCareNoInfoServiceImpl.getExceptionDetail(e);
                log.error("修改实际发送时间发生错误", sdAllWorker.getWorkerId(), e);
            }
            // 3. 添加发送记录
            try {
                tbCareNoticeLogService.addCareNoticeLog(sdAllWorker.getWorkerId(), isSuccess, exception, "普通");
            } catch (Exception e) {
                jobIsSuccess = false;
                log.error("保存日志时发生错误", sdAllWorker.getWorkerId(), e);
            }
        }

        if (!jobIsSuccess) {
            throw new AppBusinessException("定时发送通知发生错误");
        }
    }

    @Override
    public void noticeLeaderJob() {
        List<SdAllWorker> receiveNoticeLeaderList = null;
        try {
            receiveNoticeLeaderList = getReceiveNoticeLeaderList();
        } catch (Exception e) {
            log.error("获取通知领导列表失败！", e);
            throw new AppBusinessException("获取通知领导列表失败！");
        }
        Boolean jobIsSuccess = true;
        // 获取配置的文案
        TbCareNoticeSetting mailTitle = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.MAIL_CONTENT, "绩效优秀标题");
        TbCareNoticeSetting mailContent = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.MAIL_CONTENT, "绩效优秀正文");
        TbCareNoticeSetting weChatTitle = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.WECHAT_CONTENT, "绩效优秀标题");
        TbCareNoticeSetting weChatContent = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.WECHAT_CONTENT, "绩效优秀正文");
        for (SdAllWorker sdAllWorker : receiveNoticeLeaderList) {
            Boolean isSuccess = true;
            String exception = null;
            // 1. 发送消息
            try {
                // 发送邮件消息
                eosUtils.sendEosMail("zhou.pengb@h3c.com", null,
                        mailTitle.getTextValue(),
                        mailContent.getTextValue() + "( " + sdAllWorker.getWorkerName() + "|" + sdAllWorker.getWorkerId() + " )");
                // 发送企微消息
                weChatUtils.sendWeChatImageMsg("z22968",
                        weChatTitle.getTextValue(),
                        weChatContent.getTextValue() + "( " + sdAllWorker.getWorkerName() + "|" + sdAllWorker.getWorkerId() + " )",
                        weChatUtils.getWeChatOpenUrl(careIndexUrl));
            } catch (Exception e) {
                exception = TbCareNoInfoServiceImpl.getExceptionDetail(e);
                isSuccess = false;
                jobIsSuccess = false;
                log.error("发送消息失败，工号：{}", sdAllWorker.getWorkerId(), e);
            }

            // TODO 异步
            // 2. 修改数据库实际发送时间
            try {
                // 只有两个通知都发送成功，才能修改发送时间
                if (isSuccess) {
                    updateActualNoticeTimeByOldWorkId(sdAllWorker.getWorkerId(), true);
                }
            } catch (Exception e) {
                isSuccess = false;
                jobIsSuccess = false;
                exception += "/n" + TbCareNoInfoServiceImpl.getExceptionDetail(e);
                log.error("修改实际发送时间发生错误", sdAllWorker.getWorkerId(), e);
            }
            // 3. 添加发送记录
            try {
                tbCareNoticeLogService.addCareNoticeLog(sdAllWorker.getWorkerId(), isSuccess, exception, "绩效优秀");
            } catch (Exception e) {
                jobIsSuccess = false;
                log.error("保存日志时发生错误", sdAllWorker.getWorkerId(), e);
            }
        }

        if (!jobIsSuccess) {
            throw new AppBusinessException("定时发送绩效优秀通知发生错误");
        }
    }

    @Override
    public void updateActualNoticeTimeByOldWorkId(String workerId, Boolean isExcellent) {
        LambdaQueryWrapper<TbCareInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (isExcellent) {
            // 当前用户的通知中，是绩效优秀，预计通知时间小于当前时间，实际通知时间为空
            queryWrapper.eq(TbCareInfo::getType, CareInfoType.EXCELLENT_PERFORMANCE.getCode());
        } else {
            // 当前用户的通知中，不是绩效优秀，预计通知时间小于当前时间，实际通知时间为空
            queryWrapper.ne(TbCareInfo::getType, CareInfoType.EXCELLENT_PERFORMANCE.getCode());
        }
        queryWrapper.eq(TbCareInfo::getOldWorkerId, workerId)
                .le(TbCareInfo::getNoticeTime, new Date())
                .isNull(TbCareInfo::getActualNoticeTime);
        List<TbCareInfo> baseList = tbCareInfoMapper.selectList(queryWrapper);
        List<String> idList = baseList.stream().map(TbCareInfo::getId).collect(Collectors.toList());
        queryWrapper.clear();
        // 修改实际发送时间为当前时间
        queryWrapper.in(TbCareInfo::getId, idList);
        TbCareInfo tbCareInfo = new TbCareInfo();
        tbCareInfo.setActualNoticeTime(new Date());
        tbCareInfoMapper.update(tbCareInfo, queryWrapper);
    }


    /**
     * 新建事务后批量插入
     *
     * @param list
     * @return void
     * @author z22968
     * @date 2022-06-14 14:28
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void saveBatchByTransactional(List<TbCareInfo> list) {
        this.saveBatch(list);
    }

    @Override
    public List<TbCareInfo> getNoticeList(NewWorkerDTO worker) {
        String empCode = worker.getWorkerId();
        Assert.hasText(empCode, "工号不能为空");
        TbOfferWorker offerWorker = tbOfferWorkerService.getById(empCode);
        Assert.notNull(offerWorker, "没有该新员工的基本信息数据");
        // TODO 去careInfo表中查询是否存在
        List<TbCareInfo> result = new ArrayList<>();
        String inType = offerWorker.getInType();
        if (inType.equals("社会招聘")) {
            // 获取配置的 社招短周期推送人数
            TbCareNoticeSetting socialShortSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.PEOPLE_NUM, CareInfoType.SOCIAL_SHORT.getName());
            if (socialShortSetting == null) {
                throw new AppBusinessException("请配置社招人员短周期推送人数");
            }
            result = getShortCycle(worker, socialShortSetting.getValue(), CareInfoType.SOCIAL_SHORT);
            // 获取配置的 社招长周期推送人数
            TbCareNoticeSetting socialLongSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.PEOPLE_NUM, CareInfoType.SOCIAL_LONG.getName());
            if (socialLongSetting == null) {
                throw new AppBusinessException("请配置社招人员长周期推送人数");
            }
            List<TbCareInfo> longCycleList = getLongCycle(worker, socialLongSetting.getValue(), result);
            result.addAll(longCycleList);
        } else {
            // 无四级部门/四级部门不是培训营
            if (!(worker.getDept4id() != null && worker.getDept4id().intValue() == 50042529)) {
                // 获取校招推送人数
                TbCareNoticeSetting schoolSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.PEOPLE_NUM, CareInfoType.SCHOOL.getName());
                if (schoolSetting == null) {
                    throw new AppBusinessException("请配置校招人员推送人数");
                }
                result = getShortCycle(worker, schoolSetting.getValue(), CareInfoType.SCHOOL);
            } else {
                // 获取校招其他推送人数
                TbCareNoticeSetting schoolOtherSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.PEOPLE_NUM, CareInfoType.SCHOOL_OTHER.getName());
                if (schoolOtherSetting == null) {
                    throw new AppBusinessException("请配置其他校招人员推送人数");
                }
                result = getSchoolOther(worker, schoolOtherSetting.getValue());
            }
        }
        // TODO list内去重
        return result;
    }

    /**
     * 获取需要通知的123级领导名单
     *
     * @param worker
     * @return java.util.List<com.h3c.nem.entity.TbCareInfo>
     * @author z22968
     * @date 2022-06-13 09:08
     */
    private List<TbCareInfo> getNoticeLeader(NewWorkerDTO worker) {
        List<TbCareInfo> result = new ArrayList<>();
        // 获取一二三级领导
        LambdaQueryWrapper<SdDept> sdDeptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sdDeptLambdaQueryWrapper.eq(SdDept::getDeptId, worker.getDept1id());
        if (worker.getDept2id() != null) {
            sdDeptLambdaQueryWrapper.or().eq(SdDept::getDeptId, worker.getDept2id());
        }
        if (worker.getDept3id() != null) {
            sdDeptLambdaQueryWrapper.or().eq(SdDept::getDeptId, worker.getDept3id());
        }
        List<Map<String, Object>> idMap = sdDeptService.getBaseMapper().selectEmpCodes(sdDeptLambdaQueryWrapper);
        if (CollectionUtils.isEmpty(idMap)) {
            throw new AppBusinessException("未获取到该员工的123级部门领导");
        }
        result = JSONArray.parseArray(JSONArray.toJSONString(idMap), TbCareInfo.class);
        // 若一级部门有正副级领导则需要拆分成两个
        List<TbCareInfo> plus = new ArrayList<>();
        for (TbCareInfo careInfo : result) {
            if (careInfo.getOldWorkerId().contains(",")) {
                String[] workIdArr = careInfo.getOldWorkerId().split(",");
                careInfo.setOldWorkerId(workIdArr[0]);
                TbCareInfo tbCareInfo = new TbCareInfo();
                tbCareInfo.setOldWorkerId(workIdArr[1]);

                tbCareInfo.setNewWorkerId(worker.getWorkerId());
                tbCareInfo.setOriginCreateTime(worker.getOriginCreateTime());
                tbCareInfo.setType(CareInfoType.EXCELLENT_PERFORMANCE);
                tbCareInfo.setNoticeTime(new Date());
                plus.add(tbCareInfo);
            }
            careInfo.setNewWorkerId(worker.getWorkerId());
            careInfo.setOriginCreateTime(worker.getOriginCreateTime());
            careInfo.setType(CareInfoType.EXCELLENT_PERFORMANCE);
            careInfo.setNoticeTime(new Date());
        }
        if (!CollectionUtils.isEmpty(plus)) {
            result.addAll(plus);
        }
        return result;
    }

    /**
     * 获取社招短周期/校招推送人员
     *
     * @param worker 新员工信息
     * @param limit  最大人数
     * @return java.util.List<com.h3c.nem.dto.mapstruct.NewWorkerDTO>
     * @author z22968
     * @date 2022-06-08 17:45
     */
    private List<TbCareInfo> getShortCycle(NewWorkerDTO worker, Integer limit, CareInfoType careInfoType) {
        List<TbCareInfo> result = new ArrayList<>();
        Integer dept3id = worker.getDept3id();
        Assert.notNull(dept3id, "该用户无三级部门 工号：" + worker.getWorkerId());
        Integer dept4id = worker.getDept4id();
        // 获取三四级领导
        LambdaQueryWrapper<SdDept> sdDeptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sdDeptLambdaQueryWrapper.eq(SdDept::getDeptId, dept3id);
        if (dept4id != null) {
            sdDeptLambdaQueryWrapper.or().eq(SdDept::getDeptId, dept4id);
        }
        List<Map<String, Object>> idMap = sdDeptService.getBaseMapper().selectEmpCodes(sdDeptLambdaQueryWrapper);
        if (!CollectionUtils.isEmpty(idMap)) {
            result = JSONArray.parseArray(JSONArray.toJSONString(idMap), TbCareInfo.class);
        }
        // 人数不够
        if (result.size() < limit) {
            // 获取直属部门同事
            QueryWrapper<SdAllWorker> sdAllWorkerQueryWrapper = new QueryWrapper<>();
            sdAllWorkerQueryWrapper.eq("direct_dept_id", worker.getDirectDeptId());
            List<String> excludeIds = new ArrayList<>();
            // 排除自己
            excludeIds.add(worker.getWorkerId());
            getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
        }
        // 防止过多
        if (result.size() > limit) {
            result.subList(0, limit - 1);
        }
        // 获取通知发送的时间
        Date nextNoticeTime = getNextNoticeTime(careInfoType);
        for (TbCareInfo careInfo : result) {
            careInfo.setNewWorkerId(worker.getWorkerId());
            careInfo.setType(careInfoType);
            careInfo.setOriginCreateTime(worker.getOriginCreateTime());
            careInfo.setNoticeTime(nextNoticeTime);
        }
        return result;
    }

    /**
     * 获取社招长周期推送人员
     *
     * @param worker
     * @param limit
     * @param shortList
     * @return java.util.List<com.h3c.nem.entity.TbCareInfo>
     * @author z22968
     * @date 2022-06-10 11:50
     */
    private List<TbCareInfo> getLongCycle(NewWorkerDTO worker, Integer limit, List<TbCareInfo> shortList) {
        List<TbCareInfo> result = new ArrayList<>();
        // 排除短周期中的
        List<String> excludeIds = shortList.stream().map(TbCareInfo::getOldWorkerId).collect(Collectors.toList());
        // 排除自己
        excludeIds.add(worker.getWorkerId());
        QueryWrapper<SdAllWorker> sdAllWorkerQueryWrapper = new QueryWrapper<>();
        Integer dept3id = worker.getDept3id();
        Integer dept4id = worker.getDept4id();
        // 当前在四级部门且人数不够时，获取三级部门的人
        if (dept4id != null) {
            // 获取该四级部门的人数(去重短周期)
            sdAllWorkerQueryWrapper.eq("direct_dept_id", worker.getDirectDeptId())
                    .notIn("worker_id", excludeIds);
            int dept4Num = sdAllWorkerService.count(sdAllWorkerQueryWrapper);
            sdAllWorkerQueryWrapper.clear();
            // 4级部门剩余数<推送人数 则直接使用3级部门
            if ((dept4Num - excludeIds.size()) < limit) {
                sdAllWorkerQueryWrapper.eq("direct_dept_id", dept3id);
                getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
            } else {
                // 人数够直接用四级部门
                sdAllWorkerQueryWrapper.eq("direct_dept_id", dept4id);
                getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
            }
        } else {
//            // 在三级部门直接使用
//            sdAllWorkerQueryWrapper.eq("direct_dept_id", dept3id);
//            getWorkerList(result, limit, sdAllWorkerQueryWrapper);
        }

        // 同一学校
        if (result.size() < limit) {
            sdAllWorkerQueryWrapper.eq("graduate_school", worker.getGraduateSchool());
            getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
        }
        // 人数不够,获取同乡(比较身份证前4位)
        if (result.size() < limit) {
            sdAllWorkerQueryWrapper.likeRight("certificate_no_top_six", worker.getCertificateNoTopSix().substring(0, 4));
            getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
        }
        // 人数不够,获取同工作履行地
        if (result.size() < limit) {
            sdAllWorkerQueryWrapper.eq("work_city", worker.getWorkCity());
            getWorkerList(result, excludeIds, limit, sdAllWorkerQueryWrapper);
        }
        // TODO 办公区域跳过
        if (result.size() > limit) {
            result.subList(0, limit - 1);
        }
        // 获取下次通知时间
        Date maxNoticeTime = getNextNoticeTime(CareInfoType.SOCIAL_LONG);
        for (TbCareInfo careInfo : result) {
            careInfo.setNewWorkerId(worker.getWorkerId());
            careInfo.setType(CareInfoType.SOCIAL_LONG);
            careInfo.setOriginCreateTime(worker.getOriginCreateTime());
            careInfo.setNoticeTime(maxNoticeTime);
        }
        return result;
    }

    /**
     * 获取校招其他 推送人员
     *
     * @param worker
     * @param limit
     * @return java.util.List<com.h3c.nem.entity.TbCareInfo>
     * @author z22968
     * @date 2022-06-10 17:11
     */
    private List<TbCareInfo> getSchoolOther(NewWorkerDTO worker, Integer limit) {
        List<TbCareInfo> result = new ArrayList<>();
        // 获取同一批入职人员
        QueryWrapper<SdAllWorker> sdAllWorkerQueryWrapper = new QueryWrapper<>();
        sdAllWorkerQueryWrapper.eq("join_date", worker.getJoinDate());
        getWorkerList(result, null, limit, sdAllWorkerQueryWrapper);
        // 人数不够,获取 "一级部门" 入职大于 "一个月" 的新员工
        if (result.size() < limit) {
            LocalDateTime localDateTime = new LocalDateTime();
            Date before1Month = localDateTime.minusMonths(1).toDate();
            sdAllWorkerQueryWrapper.ge("join_date", before1Month)
                    .eq("dept1id", worker.getDept1id());
            getWorkerList(result, null, limit, sdAllWorkerQueryWrapper);
        }
        // 人数不够,获取 "同一学校" 入职大于 "一个月" 的新员工
        if (result.size() < limit) {
            LocalDateTime localDateTime = new LocalDateTime();
            Date before1Month = localDateTime.minusMonths(1).toDate();
            sdAllWorkerQueryWrapper.ge("join_date", before1Month)
                    .eq("graduate_school", worker.getGraduateSchool());
            getWorkerList(result, null, limit, sdAllWorkerQueryWrapper);
        }
        // 人数不够,获取 入职"6个月-2年内" 的新员工
        if (result.size() < limit) {
            Date start = new LocalDateTime().minusYears(2).toDate();
            Date end = new LocalDateTime().minusMonths(6).toDate();
            sdAllWorkerQueryWrapper.ge("join_date", start)
                    .le("join_date", end);
            getWorkerList(result, null, limit, sdAllWorkerQueryWrapper);
        }
        Date nextNoticeTime = getNextNoticeTime(CareInfoType.SCHOOL_OTHER);
        for (TbCareInfo careInfo : result) {
            careInfo.setNewWorkerId(worker.getWorkerId());
            careInfo.setType(CareInfoType.SCHOOL_OTHER);
            careInfo.setOriginCreateTime(worker.getOriginCreateTime());
            careInfo.setNoticeTime(nextNoticeTime);
        }
        return result;
    }

    /**
     * 查询AllWorker表并将结果转化成TbCareInfo
     *
     * @param curList                 当前已有人员
     * @param excludeIds              需要排除的id
     * @param limit                   限制条数
     * @param sdAllWorkerQueryWrapper 查询条件
     * @return void
     * @author z22968
     * @date 2022-06-10 11:48
     */
    private void getWorkerList(List<TbCareInfo> curList, List<String> excludeIds, Integer limit, QueryWrapper<SdAllWorker> sdAllWorkerQueryWrapper) {
        List<String> ids = curList.stream().map(TbCareInfo::getOldWorkerId).collect(Collectors.toList());
        int limitNum = limit - curList.size();
        if (!CollectionUtils.isEmpty(excludeIds)) {
            ids.addAll(excludeIds);
        }
        if (!CollectionUtils.isEmpty(ids)) {
            sdAllWorkerQueryWrapper.notIn("worker_id", ids);
        }
        Integer count = sdAllWorkerService.getBaseMapper().selectCount(sdAllWorkerQueryWrapper);
        if (count == 0) {
            sdAllWorkerQueryWrapper.clear();
            return;
        }
        // 如果sql查询总数比需要的数量多，则随机获取
        int randomStart = 0;
        if (count > limitNum) {
            int start = count - limitNum;
            Random random = new Random();
            // 随机从0-start中生成一个数字
            randomStart = random.nextInt(start + 1);
        }
        sdAllWorkerQueryWrapper.select("worker_id as old_worker_id")
                .eq("worker_type", 1)
                .last("limit " + randomStart + "," + limitNum);
        List<Map<String, Object>> maps = sdAllWorkerService.getBaseMapper().selectMaps(sdAllWorkerQueryWrapper);
        if (!CollectionUtils.isEmpty(maps)) {
            List<TbCareInfo> deptWorkers = JSONArray.parseArray(JSONArray.toJSONString(maps), TbCareInfo.class);
            curList.addAll(deptWorkers);
        }
        sdAllWorkerQueryWrapper.clear();
    }

    /**
     * 获取拉取新员工/绩效优秀新员工用的起始时间（即最近一次拉取新员工/绩效优秀新员工并添加到careInfo的时间）
     *
     * @param isExcellent 是否仅添加绩效优秀人员条件
     * @return java.util.Date
     * @author z22968
     * @date 2022-06-13 11:48
     */
    private Date getPullNewWorkerStartTime(Boolean isExcellent) {
        LambdaQueryWrapper<TbCareInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(TbCareInfo::getOriginCreateTime)
                .last("limit 1");
        if (isExcellent) {
            // 绩效优秀通知
            queryWrapper.eq(TbCareInfo::getType, CareInfoType.EXCELLENT_PERFORMANCE.getCode());
        } else {
            // 排除绩效优秀通知、和社招长周期
            queryWrapper.ne(TbCareInfo::getType, CareInfoType.EXCELLENT_PERFORMANCE.getCode());
            // TODO （？为何要排除社招长周期）
//                    .ne(TbCareInfo::getType, CareInfoType.SOCIAL_LONG.getCode());
        }

        TbCareInfo tbCareInfo = tbCareInfoMapper.selectOne(queryWrapper);
        if (tbCareInfo != null) {
            return tbCareInfo.getOriginCreateTime();
        }
        log.warn("careInfo表中无数据，使用当前时间减一个月");
        LocalDateTime localDateTime = new LocalDateTime();
        LocalDateTime minusMonths = localDateTime.minusMonths(1);
        return minusMonths.toDate();
    }

    /**
     * 根据类型获取下次发送通知时间
     *
     * @param careInfoType
     * @return java.util.Date
     * @author z22968
     * @date 2022-06-14 18:26
     */
    public Date getNextNoticeTime(CareInfoType careInfoType) {
        LambdaQueryWrapper<TbCareInfo> queryWrapper = new LambdaQueryWrapper<>();
        // 使用NoticeTime 不用actualNoticeTime，actualNoticeTime会受用户的接受通知频率而变动，导致长短周期未按照配置的间隔设置预计发送时间
        // 使用NoticeTime能够按照频率，将不在频率上的时间，放到频率对应的时间上
        // eg 短：3天 、长：5天、当前1号
        // 短周期的预计发送时间为：4，7，10，13，15 ... 一直都是+3
        // 长周期的预计发送时间为：6，12，18，24，30 ... 一直都是+6
        queryWrapper.eq(TbCareInfo::getType, careInfoType.getCode())
                .orderByDesc(TbCareInfo::getNoticeTime)
                .last("limit 1");
        TbCareInfo tbCareInfo = tbCareInfoMapper.selectOne(queryWrapper);
        LocalDate nextNoticeTime = null;
        LocalDate now = LocalDate.now();
        if (tbCareInfo != null) {
            nextNoticeTime = tbCareInfo.getNoticeTime().toInstant().atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
        }
        // 获取数据库中该类型对应的频率
        TbCareNoticeSetting noticeSetting = tbCareNoticeSettingService.selectOne(TbCareNoticeSetting.SettingType.FREQUENCY, careInfoType.getName());
        if (noticeSetting == null) {
            throw new AppBusinessException("请配置" + careInfoType.getName() + "的频率");
        }
        // 特殊处理"校招其他"
        if (careInfoType == CareInfoType.SCHOOL_OTHER) {
            // 获取本月预计发送时间
            LocalDate curMonthDay = LocalDate.now().withDayOfMonth(noticeSetting.getValue());
            // 预计发送时间 比当前时间小 则用加一个月
            if (curMonthDay.compareTo(now) < 0) {
                nextNoticeTime = curMonthDay.plusMonths(1);
            } else {
                nextNoticeTime = curMonthDay;
            }
        } else {
            if (nextNoticeTime == null) {
                nextNoticeTime = LocalDate.now().plusDays(noticeSetting.getValue());
            }
            while (nextNoticeTime.compareTo(now) < 0) {
                // 加频率，直到不小于当前时间
                nextNoticeTime = nextNoticeTime.plusDays(noticeSetting.getValue());
            }
        }
        // LocalDate 转 Date
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = nextNoticeTime.atStartOfDay(zoneId);
        return Date.from(zdt.toInstant());
    }
}
